Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Commit 520be250955e528145d37d704c8615380e751d92


Parents : 3fef4a2
Author : Ivan <ivan@quad4.io>
Signature : Signature validation error
Date : 2026-03-22T14:11:47+03:00

Remove obsolete OSV scan script and add new CI scripts for Docker, Java, Node.js, Python, and Task setup

Changes
Diff

diff --git a/scripts/ci/checkout.sh b/scripts/ci/checkout.sh
new file mode 100755
index 00000000..5c2fa39e
--- /dev/null
+++ b/scripts/ci/checkout.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# Clone and checkout using Gitea Actions environment variables.
+# Source: self-contained, no third-party dependencies.
+#
+# Usage: checkout.sh [fetch_depth]
+# fetch_depth: number of commits (default 1), or 0 for full history.
+#
+# Required env: GITEA_SERVER_URL, GITEA_REPOSITORY, GITHUB_SHA
+# Optional env: GITEA_TOKEN (for private repos), GITHUB_WORKSPACE
+set -eu
+
+FETCH_DEPTH="${1:-1}"
+SERVER="${GITEA_SERVER_URL:-${GITHUB_SERVER_URL:?GITEA_SERVER_URL not set}}"
+REPO="${GITEA_REPOSITORY:-${GITHUB_REPOSITORY:?GITEA_REPOSITORY not set}}"
+SHA="${GITHUB_SHA:?GITHUB_SHA not set}"
+TOKEN="${GITEA_TOKEN:-${GITHUB_TOKEN:-}}"
+WORKSPACE="${GITHUB_WORKSPACE:-.}"
+
+cd "$WORKSPACE"
+
+if [ -n "$TOKEN" ]; then
+ git config --global credential.helper \
+ "!f() { echo username=x-access-token; echo \"password=${TOKEN}\"; }; f"
+fi
+
+ORIGIN="${SERVER}/${REPO}.git"
+
+if [ "$FETCH_DEPTH" = "0" ]; then
+ git clone -q "$ORIGIN" .
+else
+ git init -q
+ git remote add origin "$ORIGIN"
+ git fetch -q --depth="$FETCH_DEPTH" origin "$SHA"
+fi
+
+git checkout -q "$SHA" 2>/dev/null || git checkout -q FETCH_HEAD
+
+echo "Checked out ${REPO} at $(git rev-parse --short HEAD)"

diff --git a/scripts/ci/docker-tags.sh b/scripts/ci/docker-tags.sh
new file mode 100755
index 00000000..0d5a66a6
--- /dev/null
+++ b/scripts/ci/docker-tags.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# Generate Docker image tags from git context.
+#
+# Usage: docker-tags.sh <image_name> [output_file]
+# Environment: GITEA_REF / GITHUB_REF, GITEA_REF_NAME / GITHUB_REF_NAME
+#
+# The output file contains one `-t registry/image:tag` per line,
+# suitable for passing directly to `docker buildx build`.
+set -eu
+
+IMAGE="$1"
+OUTPUT="${2:-/tmp/docker-tags.txt}"
+: > "$OUTPUT"
+
+SHA="$(git rev-parse --short HEAD)"
+REF="${GITEA_REF:-${GITHUB_REF:-}}"
+BRANCH="${GITEA_REF_NAME:-${GITHUB_REF_NAME:-$(git rev-parse --abbrev-ref HEAD)}}"
+
+echo "-t ${IMAGE}:sha-${SHA}" >> "$OUTPUT"
+
+case "$BRANCH" in
+ master|main)
+ echo "-t ${IMAGE}:latest" >> "$OUTPUT"
+ ;;
+esac
+
+case "$REF" in
+ refs/tags/v*)
+ VERSION="${REF#refs/tags/v}"
+ echo "-t ${IMAGE}:${VERSION}" >> "$OUTPUT"
+ MAJOR_MINOR="$(echo "$VERSION" | cut -d. -f1-2)"
+ if [ "$MAJOR_MINOR" != "$VERSION" ]; then
+ echo "-t ${IMAGE}:${MAJOR_MINOR}" >> "$OUTPUT"
+ fi
+ ;;
+ refs/tags/*)
+ TAG="${REF#refs/tags/}"
+ echo "-t ${IMAGE}:${TAG}" >> "$OUTPUT"
+ ;;
+esac
+
+echo "Generated tags:"
+cat "$OUTPUT"

diff --git a/scripts/ci/setup-docker.sh b/scripts/ci/setup-docker.sh
new file mode 100755
index 00000000..6e2ba125
--- /dev/null
+++ b/scripts/ci/setup-docker.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+# Set up QEMU and Docker Buildx for multi-platform builds.
+# Optionally log in to a container registry.
+#
+# Usage: setup-docker.sh [registry] [username] [password]
+# or set REGISTRY, REGISTRY_USERNAME, REGISTRY_PASSWORD env vars.
+set -eu
+
+REGISTRY="${1:-${REGISTRY:-}}"
+USERNAME="${2:-${REGISTRY_USERNAME:-}}"
+PASSWORD="${3:-${REGISTRY_PASSWORD:-}}"
+
+echo "Registering QEMU binfmt handlers"
+sudo apt-get update -qq
+sudo apt-get install -y -qq qemu-user-static binfmt-support
+
+echo "Creating Docker Buildx builder"
+docker buildx create --name multiarch --driver docker-container --use
+docker buildx inspect --bootstrap
+
+if [ -n "$REGISTRY" ] && [ -n "$USERNAME" ] && [ -n "$PASSWORD" ]; then
+ echo "Logging in to ${REGISTRY}"
+ echo "$PASSWORD" | docker login "$REGISTRY" -u "$USERNAME" --password-stdin
+fi

diff --git a/scripts/ci/setup-java.sh b/scripts/ci/setup-java.sh
new file mode 100755
index 00000000..d22c2bac
--- /dev/null
+++ b/scripts/ci/setup-java.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+# Install Adoptium Temurin JDK with SHA256 verification.
+# Uses the Adoptium assets API to obtain the checksum and download URL
+# directly from the source, avoiding opaque redirects.
+# Source: https://adoptium.net (Eclipse Foundation)
+# Usage: setup-java.sh [major_version]
+set -eu
+
+JAVA_VERSION="${1:-17}"
+
+ARCH="$(uname -m)"
+case "$ARCH" in
+ x86_64) ARCH="x64" ;;
+ aarch64) ARCH="aarch64" ;;
+ *) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;;
+esac
+
+echo "Installing Temurin JDK ${JAVA_VERSION} (${ARCH})"
+
+ASSETS_API="https://api.adoptium.net/v3/assets/latest/${JAVA_VERSION}/hotspot?architecture=${ARCH}&image_type=jdk&os=linux&vendor=eclipse"
+API_JSON="$(curl -fsSL "$ASSETS_API")"
+
+DOWNLOAD_URL="$(echo "$API_JSON" | sed -n 's/.*"link" *: *"\([^"]*\)".*/\1/p' | head -1)"
+CHECKSUM_URL="$(echo "$API_JSON" | sed -n 's/.*"checksum_link" *: *"\([^"]*\)".*/\1/p' | head -1)"
+EXPECTED="$(echo "$API_JSON" | sed -n 's/.*"checksum" *: *"\([0-9a-f]*\)".*/\1/p' | head -1)"
+
+if [ -z "$DOWNLOAD_URL" ] || [ -z "$EXPECTED" ]; then
+ echo "Failed to resolve Temurin JDK ${JAVA_VERSION} for ${ARCH}" >&2
+ exit 1
+fi
+
+curl -fsSL "$DOWNLOAD_URL" -o /tmp/jdk.tar.gz
+
+ACTUAL="$(sha256sum /tmp/jdk.tar.gz | cut -d' ' -f1)"
+if [ "$EXPECTED" != "$ACTUAL" ]; then
+ echo "SHA256 verification failed for JDK ${JAVA_VERSION}" >&2
+ echo " expected: ${EXPECTED}" >&2
+ echo " got: ${ACTUAL}" >&2
+ rm -f /tmp/jdk.tar.gz
+ exit 1
+fi
+echo "SHA256 verified: ${ACTUAL}"
+
+if [ -n "$CHECKSUM_URL" ]; then
+ EXPECTED_LINK="$(curl -fsSL "$CHECKSUM_URL" | cut -d' ' -f1)"
+ if [ "$EXPECTED_LINK" != "$ACTUAL" ]; then
+ echo "Cross-check against checksum_link also failed" >&2
+ rm -f /tmp/jdk.tar.gz
+ exit 1
+ fi
+ echo "Cross-verified against checksum_link"
+fi
+
+sudo mkdir -p /opt/java
+sudo tar -xzf /tmp/jdk.tar.gz -C /opt/java --strip-components=1
+rm -f /tmp/jdk.tar.gz
+
+CI_ENV="${GITEA_ENV:-${GITHUB_ENV:-/dev/null}}"
+CI_PATH="${GITEA_PATH:-${GITHUB_PATH:-/dev/null}}"
+echo "JAVA_HOME=/opt/java" >> "$CI_ENV"
+echo "/opt/java/bin" >> "$CI_PATH"
+
+export JAVA_HOME=/opt/java
+export PATH="/opt/java/bin:$PATH"
+java -version

diff --git a/scripts/ci/setup-node.sh b/scripts/ci/setup-node.sh
new file mode 100755
index 00000000..5625d5d2
--- /dev/null
+++ b/scripts/ci/setup-node.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+# Install Node.js from the official binary distribution with SHA256 verification.
+# Source: https://nodejs.org
+# Usage: setup-node.sh [major_version]
+set -eu
+
+NODE_MAJOR="${1:-24}"
+
+ARCH="$(uname -m)"
+case "$ARCH" in
+ x86_64) ARCH="x64" ;;
+ aarch64) ARCH="arm64" ;;
+ armv7l) ARCH="armv7l" ;;
+ *) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;;
+esac
+
+DIST_URL="https://nodejs.org/dist/latest-v${NODE_MAJOR}.x"
+
+curl -fsSL "${DIST_URL}/SHASUMS256.txt" -o /tmp/node-shasums.txt
+
+VERSION="$(grep -o "node-v[0-9.]*-linux-${ARCH}" /tmp/node-shasums.txt \
+ | head -1 \
+ | sed "s/-linux-${ARCH}//" \
+ | sed 's/node-//')"
+
+if [ -z "$VERSION" ]; then
+ echo "Failed to resolve Node.js v${NODE_MAJOR} for ${ARCH}" >&2
+ exit 1
+fi
+
+TARBALL="node-${VERSION}-linux-${ARCH}.tar.xz"
+echo "Installing Node.js ${VERSION} (${ARCH})"
+curl -fsSL "${DIST_URL}/${TARBALL}" -o /tmp/node.tar.xz
+
+EXPECTED="$(grep " ${TARBALL}\$" /tmp/node-shasums.txt | cut -d' ' -f1)"
+ACTUAL="$(sha256sum /tmp/node.tar.xz | cut -d' ' -f1)"
+if [ -z "$EXPECTED" ] || [ "$EXPECTED" != "$ACTUAL" ]; then
+ echo "SHA256 verification failed for ${TARBALL}" >&2
+ echo " expected: ${EXPECTED}" >&2
+ echo " got: ${ACTUAL}" >&2
+ rm -f /tmp/node.tar.xz /tmp/node-shasums.txt
+ exit 1
+fi
+echo "SHA256 verified: ${ACTUAL}"
+
+sudo tar -xJf /tmp/node.tar.xz -C /usr/local --strip-components=1
+rm -f /tmp/node.tar.xz /tmp/node-shasums.txt
+
+node --version
+npm --version

diff --git a/scripts/ci/setup-pnpm.sh b/scripts/ci/setup-pnpm.sh
new file mode 100755
index 00000000..ce2ddba9
--- /dev/null
+++ b/scripts/ci/setup-pnpm.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+# Activate pnpm via corepack.
+# Usage: setup-pnpm.sh [version]
+set -eu
+
+PNPM_VERSION="${1:-10.30.0}"
+
+corepack enable
+corepack prepare "pnpm@${PNPM_VERSION}" --activate
+
+pnpm --version

diff --git a/scripts/ci/setup-python.sh b/scripts/ci/setup-python.sh
new file mode 100755
index 00000000..03ee3718
--- /dev/null
+++ b/scripts/ci/setup-python.sh
@@ -0,0 +1,97 @@
+#!/bin/sh
+# Build and install Python from official python.org source with GPG verification.
+# Source: https://www.python.org
+#
+# Usage: setup-python.sh [version]
+# version: exact (3.13.9) or minor (3.13, resolved to latest patch).
+set -eu
+
+PY_INPUT="${1:-3.13}"
+
+CURRENT="$(python3 --version 2>/dev/null | sed 's/Python //')" || true
+
+case "$PY_INPUT" in
+ *.*.*)
+ PY_VERSION="$PY_INPUT"
+ ;;
+ *)
+ echo "Resolving latest Python ${PY_INPUT}.x from python.org"
+ PY_VERSION="$(curl -fsSL "https://www.python.org/ftp/python/" \
+ | grep -o "href=\"${PY_INPUT}\.[0-9]*/" \
+ | sed 's/href="//;s/\///' \
+ | sort -t. -k3 -n \
+ | tail -1)"
+ if [ -z "$PY_VERSION" ]; then
+ echo "Failed to resolve Python ${PY_INPUT}.x" >&2
+ exit 1
+ fi
+ echo "Resolved to ${PY_VERSION}"
+ ;;
+esac
+
+if [ "$CURRENT" = "$PY_VERSION" ]; then
+ echo "Python ${PY_VERSION} already installed"
+ python3 --version
+ exit 0
+fi
+
+echo "Building Python ${PY_VERSION} from source (python.org)"
+
+sudo apt-get update -qq
+sudo apt-get install -y -qq \
+ build-essential gnupg curl \
+ libssl-dev zlib1g-dev libbz2-dev libreadline-dev \
+ libsqlite3-dev libffi-dev liblzma-dev libncurses-dev > /dev/null 2>&1
+
+TARBALL="Python-${PY_VERSION}.tar.xz"
+SRC_URL="https://www.python.org/ftp/python/${PY_VERSION}/${TARBALL}"
+SIG_URL="${SRC_URL}.asc"
+
+curl -fsSL "$SRC_URL" -o "/tmp/${TARBALL}"
+curl -fsSL "$SIG_URL" -o "/tmp/${TARBALL}.asc"
+
+GPG_KEYS=""
+case "$PY_VERSION" in
+ 3.13.*|3.14.*)
+ GPG_KEYS="A035C8C19219BA821ECEA86B64E628F8D684696D 7169605F62C751356D054A26A821E680E5FA6305"
+ ;;
+ 3.11.*|3.12.*)
+ GPG_KEYS="A035C8C19219BA821ECEA86B64E628F8D684696D 7169605F62C751356D054A26A821E680E5FA6305"
+ ;;
+ 3.9.*|3.10.*)
+ GPG_KEYS="E3FF2839C048B25C084DEBE9B26995E310250568"
+ ;;
+ *)
+ echo "No known GPG key for Python ${PY_VERSION}; skipping signature check" >&2
+ ;;
+esac
+
+if [ -n "$GPG_KEYS" ]; then
+ export GNUPGHOME="$(mktemp -d)"
+ for key in $GPG_KEYS; do
+ gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" 2>/dev/null || \
+ gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" 2>/dev/null || true
+ done
+ gpg --batch --verify "/tmp/${TARBALL}.asc" "/tmp/${TARBALL}"
+ rm -rf "$GNUPGHOME"
+ unset GNUPGHOME
+ echo "GPG signature verified"
+fi
+
+cd /tmp
+tar -xJf "${TARBALL}"
+cd "Python-${PY_VERSION}"
+
+BUILD_LOG="/tmp/python-build.log"
+./configure --prefix=/usr/local --with-ensurepip=install > "$BUILD_LOG" 2>&1
+make -j"$(nproc)" >> "$BUILD_LOG" 2>&1
+sudo make install >> "$BUILD_LOG" 2>&1
+
+sudo ln -sf /usr/local/bin/python3 /usr/local/bin/python
+sudo ln -sf /usr/local/bin/pip3 /usr/local/bin/pip
+
+cd /
+rm -rf "/tmp/${TARBALL}" "/tmp/${TARBALL}.asc" "/tmp/Python-${PY_VERSION}" "$BUILD_LOG"
+
+python3 --version
+pip3 --version

diff --git a/scripts/ci/setup-task.sh b/scripts/ci/setup-task.sh
new file mode 100755
index 00000000..f2534e5f
--- /dev/null
+++ b/scripts/ci/setup-task.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# Install go-task from GitHub releases with SHA256 verification.
+# Source: https://github.com/go-task/task
+# Usage: setup-task.sh [version]
+set -eu
+
+TASK_VERSION="${1:-3.49.1}"
+
+ARCH="$(uname -m)"
+case "$ARCH" in
+ x86_64) ARCH="amd64" ;;
+ aarch64) ARCH="arm64" ;;
+ *) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;;
+esac
+
+BASE_URL="https://github.com/go-task/task/releases/download/v${TASK_VERSION}"
+TARBALL="task_linux_${ARCH}.tar.gz"
+
+echo "Installing Task v${TASK_VERSION} (${ARCH})"
+curl -fsSL "${BASE_URL}/task_checksums.txt" -o /tmp/task-checksums.txt
+curl -fsSL "${BASE_URL}/${TARBALL}" -o /tmp/task.tar.gz
+
+EXPECTED="$(grep " ${TARBALL}\$" /tmp/task-checksums.txt | cut -d' ' -f1)"
+ACTUAL="$(sha256sum /tmp/task.tar.gz | cut -d' ' -f1)"
+if [ -z "$EXPECTED" ] || [ "$EXPECTED" != "$ACTUAL" ]; then
+ echo "SHA256 verification failed for ${TARBALL}" >&2
+ echo " expected: ${EXPECTED}" >&2
+ echo " got: ${ACTUAL}" >&2
+ rm -f /tmp/task.tar.gz /tmp/task-checksums.txt
+ exit 1
+fi
+echo "SHA256 verified: ${ACTUAL}"
+
+sudo tar -xzf /tmp/task.tar.gz -C /usr/local/bin task
+rm -f /tmp/task.tar.gz /tmp/task-checksums.txt
+
+task --version

diff --git a/scripts/osv_scan.sh b/scripts/osv_scan.sh
deleted file mode 100644
index d62e1f07..00000000
--- a/scripts/osv_scan.sh
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-OSV_VERSION="${OSV_VERSION:-v2.3.1}"
-
-echo "Installing OSV-Scanner ${OSV_VERSION}..."
-curl -sSL "https://github.com/google/osv-scanner/releases/download/${OSV_VERSION}/osv-scanner_linux_amd64" -o /tmp/osv-scanner
-chmod +x /tmp/osv-scanner
-sudo mv /tmp/osv-scanner /usr/local/bin/osv-scanner
-
-echo "Running OSV-Scanner recursively..."
-OSV_JSON="$(mktemp)"
-trap 'rm -f "$OSV_JSON"' EXIT
-
-osv-scanner --recursive ./ --format json > "$OSV_JSON" || true
-
-if ! command -v jq >/dev/null 2>&1; then
- echo "Error: jq is not installed. Please install jq to parse OSV results."
- exit 1
-fi
-
-VULNS=$(jq -r '
- .results[]? |
- .source as $src |
- .vulns[]? |
- "\(.id) (source: \($src))"
-' "$OSV_JSON")
-
-if [ -n "$VULNS" ]; then
- echo "OSV scan found vulnerabilities:"
- echo "$VULNS" | while IFS= read -r line; do
- echo " - $line"
- done
- exit 1
-else
- echo "OSV scan: no vulnerabilities found."
-fi
-


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────